/* j-engine3d / a simple java 3d engine
Copyright (C) 2008 to present / Julien Lavergne / lavergne.julien@gmail.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*/

package scene;


import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;

import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;



import javax.media.opengl.AWTGraphicsConfiguration;
import javax.media.opengl.AWTGraphicsDevice;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;

import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLJPanel;





import com.sun.opengl.util.BufferUtil;
import com.sun.opengl.util.FPSAnimator;
import com.sun.opengl.util.j2d.Overlay;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;






public final class GLScene3D implements GLEventListener {


	public double name;

	/**
     *
     */
    private static final long serialVersionUID = 1L;

    double scale = 1;

	private GLCapabilities caps;

    protected CountFPS countfps;

    protected int ancWidth, ancHeight;

    private GLJPanel canvas;


    private Overlay infoOverlay;
    private Font font;

	public int fps = 0;

	private IntBuffer selectBuffer;

    private ArrayList<AbstractCamera> listCameras;

    private JPopupMenu popup;



    public boolean isFullscreen = false;

    private int numCurrentCamera = 0;

    // OpenGL
    private GLDrawable drawable;  // the rendering 'surface'
    public GLContext context ;    // the rendering context (holds rendering state info)

    /**
     * pour la stereoscopie
     */
    boolean isVueCroisee = false;
    KeyStereoCamera keyCamera;
    private static final float LIGHT_DIR[] =  {1.0f, 1.0f, 1.0f, 0.0f};
    // right, top, front directional light
    /**
     * FIN DECLARATION ET/OU INITIALISATION
     * POUR LA STEREOSCOPIE
     */


    /**
     * num�ro de l'objet s�lectionn�
     * selection<-0 pour aucun objet s�lectionn�
     */
    private Vector selections = new Vector();
    private int selection = -1;
    public Point mouseCoordXY = new Point();
    public Point dragMouseCoordXY = new Point();
    protected int px,py;
    protected int rx,ry;
    boolean selectionMultiple = false;

    /**
     * d�finir les valeurs d'�chelle par d�faut
     */
    double zNear = -60.0;
    double zFar = 60.0;
    double xNear = -1;
    double xFar = 1;
    double yNear = -1;
    double yFar = 1;


    boolean pickOne=false,pickZone=false;
    boolean traitementSelection = false;



    private final static int BUFSIZE = 4096;


    private Scene3DUtilisateurInterface scene3DUtilisateur;



    public GLScene3D(Scene3DUtilisateurInterface _scene3d)
    {
    	/**
    	 * appel au constructeur par d�faut
    	 */
    	this();




    	/**
    	 * on pr�cise la classe Scene3DUtilisateur
    	 */
    	this.setScene3DUtilisateur(_scene3d);


    }




    public GLScene3D()
    {

    	name = 1;


        this.caps = new GLCapabilities();
        caps.setSampleBuffers(true);
        caps.setNumSamples(4);

        /**
         * activer le double buffer,
         * desactiver la stereo et activer l'acceleration
         * materielle
         */
    	caps.setStereo(false);
        caps.setDoubleBuffered(true);
        caps.setHardwareAccelerated(true);
        caps.setAlphaBits(8);
        caps.setStencilBits(8);
        caps.setDepthBits(24);

        this.setCanvas(new GLJPanel(caps));



        AWTGraphicsDevice dev = new AWTGraphicsDevice(null);
        AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration)
           GLDrawableFactory.getFactory().chooseGraphicsConfiguration(caps, null, dev);

        GraphicsConfiguration config = null;
        if (awtConfig != null)
          config = awtConfig.getGraphicsConfiguration();

        // get a rendering surface and a context for this canvas
        drawable = GLDrawableFactory.getFactory().getGLDrawable(getCanvas(), caps, null);
        infoOverlay = new Overlay(drawable);
        font = new Font("Courier", Font.BOLD, 14);
        //context = this.getCanvas().getContext();

        /**
         * on initialise les valeurs hauteur et largeur pour
         * appliquer ensuite getOrthogonalDisplay
         */
        ancWidth=getCanvas().getWidth();
        ancHeight=getCanvas().getHeight();



        /**
         * initialiser le conteneur � cam�ras
         */
        this.setListCameras(new ArrayList<AbstractCamera>());



        /**
         * initialisation d'un compteur pour
         * connaitre le nombre de fps
         */
        countfps = new CountFPS();


		/**
		 * Cr�ation de l'Animator
		 * comme expliqu� dans l'article
		 */
		FPSAnimator animator = new FPSAnimator(this.getCanvas(),30);
	    //animator.setRunAsFastAsPossible(true);


		/**
		 * Nous d�marrons l'Animator qui
		 * va se charger de faire des appels
		 * � la m�thode display();
		 */
		animator.start();




		/**
		 * enregistrer les �couteurs
		 */
        this.getCanvas().addGLEventListener(this);
        GLScene3DKeyHandler keyHandler = new GLScene3DKeyHandler(this);
        this.getCanvas().addKeyListener(keyHandler);
        GLScene3DMouseHandler mouseHandler = new GLScene3DMouseHandler(this);
        this.getCanvas().addMouseListener(mouseHandler);
        this.getCanvas().addMouseMotionListener(mouseHandler);
        this.getCanvas().addMouseWheelListener(mouseHandler);



     	this.setListCameras(new ArrayList<AbstractCamera>());

        /**
         * CAMERAS
         */
        /**
         * d�finition de la cam�ra 1
         * Cam�ra Sph�rique
         */
        this.addCamera(new CameraSpherique(this,0,0,10f,0,0,0));
        /**
         * d�finition de la cam�ra 2
         * Cam�ra Walk
         */
        float distanceFromCameraToEye=1f;
        this.addCamera(new CameraWalk(this,1,1,1,1-distanceFromCameraToEye,1-distanceFromCameraToEye,1-distanceFromCameraToEye));
        /**
         * d�finition de la cam�ra 3
         * Cam�ra Walk
         */
        float distanceZ=1f;
        this.addCamera(new Camera2D(this,0,0,distanceZ,0,0,0));
        /**
         * on choisit la premi�re cam�ra d�finie par d�faut
         */
        this.setCurrentCamera(0);
        /**
         * d�finir cam�ra courante pour scene3DUtilisateur
         */

        /**
         * FIN CAMERAS
         */

		getCanvas().addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {


        		/**
        		 * focus sur le canvas
        		 */
        		getCanvas().setFocusable(true);
        		getCanvas().setRequestFocusEnabled(true);
        		getCanvas().requestFocusInWindow();
        		getCanvas().requestFocus(true);
        		getCanvas().requestFocus();
            }
        });



		getCanvas().addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
            	if(e.getKeyCode()==KeyEvent.VK_E)
            	{
            	System.out.println("NAME GLSCENE3D " + name);

            	}
            }
        });


//         ActionListener al = new ActionListener() {
//      public void actionPerformed(ActionEvent e) {
//        //t.setText(((JMenuItem) e.getSource()).getText());
//      }
//    };
//    popup = new JPopupMenu();
//    JMenuItem m = new JMenuItem("Hither");
//    m.addActionListener(al);
//    popup.add(m);
//    m = new JMenuItem("Yon");
//    m.addActionListener(al);
//    popup.add(m);
//    m = new JMenuItem("Afar");
//    m.addActionListener(al);
//    popup.add(m);
//    popup.addSeparator();
//    m = new JMenuItem("Stay Here");
//    m.addActionListener(al);
//    popup.add(m);
//      class PopupListener extends MouseAdapter {
//    public void mousePressed(MouseEvent e) {
//      maybeShowPopup(e);
//    }
//
//    public void mouseReleased(MouseEvent e) {
//      maybeShowPopup(e);
//    }
//
//    private void maybeShowPopup(MouseEvent e) {
//      if (e.isPopupTrigger())
//        popup.show(e.getComponent(), e
//            .getX(), e.getY());
//    }
//  }
//    PopupListener pl = new PopupListener();
//    this.getCanvas().addMouseListener(pl);




    }




    public double getScale() {
        return scale;
    }


    public void setScale(double _scale) {
        scale = _scale;
    }


    /**
     * reshape() sera appel�e si la fen�tre d'affichage est redimensionn�e
     */
    public void reshape(GLAutoDrawable glDrawable, int x, int y, int width, int height)

    {

        final GL gl = glDrawable.getGL();





        //System.out.println("Width : "+width+" Height: "+height);

        if(height <= 0)

            height = 1;




        //this.getOrthogonalDisplay();



        if(isStereo())
        {
            // Update the viewport and frustum dimensions in the eye cameras
            keyCamera.updateViewVals(width,height);
        }

		/**
		 * focus sur le canvas
		 */
		getCanvas().setFocusable(true);
		getCanvas().setRequestFocusEnabled(true);
		getCanvas().requestFocusInWindow();
		getCanvas().requestFocus(true);
		getCanvas().requestFocus();


		/**
		 * on met � jour ancWidth et ancHeight
		 */
        ancWidth=width;
        ancHeight=height;



    }

    public void init(GLAutoDrawable drawable) {




        /**
         * GLEventListener renvoie un contexte (drawable)
         * que nous allons utiliser pour instancier un objet
         * de type GL, qui nous permettra d'utiliser
         * les fonctions OpenGL, bien que dans cet article
         * cela reste encore inutile
         */
        final GL gl = drawable.getGL();



        /**
         * Cette fonction permet de d�sactiver
         * la syncronisation verticale, ind�pendemment
         * de la plateforme utilis�e
         */
        //gl.setSwapInterval(1);



        /**
         * type de polygone
         */
        gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_POLYGON);
        /**
         * type d'ombrage : facettes ou lisse
         */
        gl.glShadeModel(gl.GL_SMOOTH);
        gl.glEnable(gl.GL_LINE_SMOOTH);
        gl.glEnable(gl.GL_POINT_SMOOTH_HINT);
        gl.glEnable(GL.GL_MULTISAMPLE);
        /**
         * activer le test de profondeur
         */
        gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDepthFunc(GL.GL_LEQUAL);                // Le type de test de profondeur a effectuer LESS ou LEQUAL??
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT|GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST);  // Le calcul des perspectives jolies



        gl.glClearDepth(1.0);
        gl.glDepthRange(0.0, 1.0); /* default z-mapping */
        /**
         * culling
         */
        //gl.glEnable(gl.GL_CULL_FACE); // Activation du culling
        //gl.glCullFace(gl.GL_BACK); // Culling des faces dont la normale est orient�e � l'encontre du sens de la cam�ra
        /**
         * activer transparence
         */
        gl.glBlendFunc(GL.GL_SRC_ALPHA,gl.GL_ONE_MINUS_SRC_ALPHA) ;
        gl.glEnable(GL.GL_BLEND);
        /* select clearing color (background) color */
        this.getScene3DUtilisateur().definirCouleurDeFond(gl);
        /**
         * arguments pour le dessin de base ligne et point
         */
        gl.glLineWidth(0.05f);
        gl.glPointSize(1.f);



        /**
         * d�finition des lumi�res et initialisation
         */
        float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
        float[] lightAmbient = {1f, 1f, 1f, 1.0f};
        float[] lightSpecular = {1f, 1f, 1f, 1.0f};
        float[] lightPosition0 = {this.getCurrentCamera().getEyeX(),
                this.getCurrentCamera().getEyeY(),
                this.getCurrentCamera().getEyeZ(),
                0f};

        //Ambient light component
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, lightAmbient,0);
        //Diffuse light component
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, lightDiffuse,0);

        gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, lightSpecular,0);

        //Light position
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition0,0);

        //Enable the first light and the lighting mode
        gl.glEnable(GL.GL_LIGHT0);
        gl.glEnable(GL.GL_LIGHTING);





        /**
         * initialisation de la configuration de la sc�ne
         * et premi�re disposition de la cam�ra
         * (normalement reshape est appel�e une premi�re fois
         * au lancement)
         */
        this.getCurrentCamera().positionner(gl);


        /**
         * partie du code pour la stereoscopie
         */
        if(isStereo())
        {
        	/**
        	 * initialisation
        	 */
            keyCamera = new KeyStereoCamera(gl, Dessin.glu, isVueCroisee);

            // Update the viewport and frustum dimensions in the eye cameras
            keyCamera.updateViewVals(this.getCanvas().getWidth(), this.getCanvas().getHeight());
        }


        /**
         * initialiser les DisplayLists
         */
        Dessin.initDessinDisplayLists(gl);
        this.getScene3DUtilisateur().initialiserMesDisplayLists(gl);




    }



    public void display(GLAutoDrawable drawable) {




    	this.getCountfps().start();

        GL gl = drawable.getGL();


        /**
         * effacer la sc�ne
         */
        //gl.glClear(GL.GL_COLOR_BUFFER_BIT);
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        /**
         * couleur du fond de la scène
         */
        this.getScene3DUtilisateur().definirCouleurDeFond(gl);

        if(isStereo())
        {
        	this.getCurrentCamera().setStereo(true);
//
//
//
        	gl.glDrawBuffer(GL.GL_BACK_LEFT);
//            /* clear all pixels */
//            gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
//
//        	//rouge
            //gl.glColorMask(true,false,false,true);//gl.GL_TRUE, gl.GL_FALSE, gl.GL_FALSE, gl.GL_TRUE);
//
//            //renderEyeScene(gl, EyeCamera.LEFT_EYE);  // left eye view of scene
//
        	this.getCurrentCamera().setTypeOeil(false);
//            /**
//             * mise � jour de la position de la cam�ra par d�faut
//             */
            this.getCurrentCamera().positionner(gl);
//
//
            if(this.getCurrentCamera().name.compareTo("2D")==0) gl.glScaled(scale, scale, scale);
            else gl.glScaled(1, 1, 1);
//
//            gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
//            /**
//             * on affiche ce que l'on d�sire
//             */
            gl.glColorMask(false,true,true,true);//gl.GL_TRUE, gl.GL_FALSE, gl.GL_FALSE, gl.GL_TRUE);
            afficherDansDisplay(gl,GL.GL_RENDER);

            gl.glFlush();


        	//gl.glDrawBuffer(GL.GL_BACK_RIGHT);

            //renderEyeScene(gl, EyeCamera.RIGHT_EYE);  // left eye view of scene

            gl.glClear(gl.GL_DEPTH_BUFFER_BIT);
            //gl.glEnable(gl.GL_BLEND);
            //gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE);

            //bleu


        	gl.glDrawBuffer(GL.GL_BACK_RIGHT);

        	this.getCurrentCamera().setTypeOeil(true);
            /**
             * mise � jour de la position de la cam�ra par d�faut
             */
            this.getCurrentCamera().positionner(gl);

            if(this.getCurrentCamera().name.compareTo("2D")==0) gl.glScaled(scale, scale, scale);
            else gl.glScaled(1, 1, 1);
            //gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

            /**
             * on affiche ce que l'on d�sire
             */
            gl.glColorMask(true,false,false,true);
            afficherDansDisplay(gl,GL.GL_RENDER);



            gl.glColorMask(true,true,true,true);

        	//drawable.swapBuffers();
        }
        else
        {
        	this.getCurrentCamera().setStereo(false);

            /**
             * mise � jour de la position de la cam�ra par d�faut
             */
            this.getCurrentCamera().positionner(gl);


            if(this.getCurrentCamera().name.compareTo("2D")==0) gl.glScaled(scale, scale, scale);
            else gl.glScaled(1, 1, 1);


            /**
             * on affiche ce que l'on d�sire
             */
            afficherDansDisplay(gl,GL.GL_RENDER);

        }




        /**
         * S�lection d'un objet avec le clic gauche
         */
        if (pickOne)
        {
        	selections.removeAllElements();
    		for(int x=px; x<rx; x+=10)
    		{
    			for(int y=py; y<ry; y+=10)
    			{
    				this.pickObjets(gl,x,y);




    			}


    		}

    		/**
    		 * on affiche le contenu du conteneur selections
    		 */
    		Iterator it = selections.iterator();
    		while(it.hasNext())
    		{
    			int _selection = (Integer)(it.next());


    			System.out.print(_selection+" ");

    		}
    		System.out.println();

    		System.out.println("taille selection="+selections.size());
    		/**
    		 * le parcours de la zone de s�lection est termin�
    		 */
    		pickOne=false;
        }





        /**
         * Travail sur le picking d'objets 3D en opengl
         */
        if (pickZone)
        {
        	selections.removeAllElements();
    		for(int x=px; x<rx; x+=10)
    		{
    			for(int y=py; y<ry; y+=10)
    			{
    				this.pickObjets(gl,x,y);




    			}


    		}

    		/**
    		 * on affiche le contenu du conteneur selections
    		 */
//    		Iterator it = selections.iterator();
//    		while(it.hasNext())
//    		{
//    			int _selection = (Integer)(it.next());
//
//
//    			System.out.print(_selection+" ");
//
//    		}
//    		System.out.println();
//
//    		System.out.println("taille selection="+selections.size());
    		/**
    		 * le parcours de la zone de s�lection est termin�
    		 */
    		pickZone=false;
        }




        if(isStereo())
        {
            /**
             * afficher panel 2D d'infos
             */
            showOverlayInfo(gl);
        	drawable.swapBuffers();
        }
        else
        {
            /**
             * afficher panel 2D d'infos
             */
            showOverlayInfo(gl);
        	gl.glFlush();
        }






        this.getCountfps().stop();
        fps = this.getCountfps().nbFPS();



    }

    /**
     * displayChanged() est appel�e si le mode d'affichage par exemple
     * est modifi�. Cependant nous n'impl�menterons pas cette m�thode.
     */
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,
            boolean deviceChanged) {


    	System.out.println("affichage modifie ??");

    }






    public AbstractCamera getCurrentCamera() {
        return this.getListCameras().get(numCurrentCamera);
    }

    protected void changerCurrentCamera()
    {
    	this.setCurrentCamera((numCurrentCamera+1)%this.getListCameras().size());

    }

    private void setCurrentCamera(int  numcamera) {
    	/**
    	 * d�sactiver la cam�ra actuelle
    	 */
    	this.removeKeyHandlerCamera(this.getCurrentCamera());
    	this.removeMouseHandlerCamera(this.getCurrentCamera());
    	/**
    	 * d�finir et activer la nouvelle cam�ra
    	 */
        this.numCurrentCamera = numcamera;
        this.addKeyHandlerCamera(this.getCurrentCamera());
        this.addMouseHandlerCamera(this.getCurrentCamera());

    }

    private void addCamera(AbstractCamera _camera)
    {
    	try{
    	this.getListCameras().add(_camera);
    	}
    	catch(Exception e)
    	{
    		System.out.println(e.getMessage());

    	}

    }



//	/**
//	 * mise � jour de l'�chelle
//	 * @param gl
//	 */
//	private void miseEchelleScene(GL gl)
//	{
//	        if(this.getScale()!=0)
//	        {
//
//
////	           xNear=-this.getCurrentCamera().getRayon();
////	           xFar=this.getCurrentCamera().getRayon();
////	           yNear=-this.getCurrentCamera().getRayon();
////	           yFar=this.getCurrentCamera().getRayon();
//	            xNear = xNear*getScale();
//	            yNear = yNear*getScale();
//	            yFar = yFar*getScale();
//	            xFar = xFar*getScale();
//	            /**
//	             * ne pas mettre � jour les zNear et zFar via la modification
//	             * du zoom sur la sc�ne
//	             */
//	            //zNear = zNear*getScale();
//	            //zFar = zFar*getScale();
//
//	            //gl.glScaled(getScale(),getScale(),getScale());
//	            //this.getCurrentCamera().setRayon((float) (this.getCurrentCamera().getRayon()*getScale()));
//
//	            setScale(0);
//	        }
//
//	}
//











	/**
	 * on d�tecte les objets
	 * @param gl
	 */
	private void pickObjets(GL gl,int _x,int _y)
	{



		int hits;
		int viewport[] = new int[4];
		int[] selectBuf = new int[BUFSIZE];

		selectBuffer = BufferUtil.newIntBuffer(BUFSIZE);
		gl.glSelectBuffer(BUFSIZE, selectBuffer);
		gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);

		gl.glRenderMode(GL.GL_SELECT);

		/**
		 * This function creates an empty name stack. You are required to call
		 *  this function to initialize the stack prior to pushing names
		 */
        gl.glInitNames();


        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();
        gl.glLoadIdentity();

        Dessin.glu.gluPickMatrix((double) _x,
				(double) (viewport[3]-_y),
				10.0, 10.0, viewport, 0);

        if(this.getCurrentCamera().name.compareTo("2D")!=0)
        {
        gl.glOrtho(xNear/(ancHeight)*this.getCanvas().getWidth(),xFar/(ancHeight)*this.getCanvas().getWidth(),
    			yNear/(ancHeight)*this.getCanvas().getHeight(),yFar/(ancHeight)*this.getCanvas().getHeight(),
    			zFar,zNear);
        Dessin.glu.gluPerspective(30, this.getCanvas().getWidth()/this.getCanvas().getHeight(), 1, 100);
        }
        else  gl.glOrtho(xNear/(ancHeight)*this.getCanvas().getWidth(),xFar/(ancHeight)*this.getCanvas().getWidth(),
    			yNear/(ancHeight)*this.getCanvas().getHeight(),yFar/(ancHeight)*this.getCanvas().getHeight(),
    			zFar,zNear);

        gl.glMatrixMode(GL.GL_MODELVIEW);

        /**
         * on dessiner en mode SELECT
         */
        afficherDansDisplay(gl,GL.GL_SELECT);


        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPopMatrix();
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glFlush();

        hits = gl.glRenderMode(GL.GL_RENDER);
        selectBuffer.get(selectBuf);
        processHits(hits);



	}

	/**
	 * on identifie les objets s�lectionn�s
	 * @param hits
	 * @param buffer
	 */
	private void processHits(int hits)
	{
		int names, ptr = 0;

		//if(hits>1) System.out.println("hits = "+hits);

		int offset=0;


		for (int i = 0; i < hits; i++)
		{

//			/**
//			 * afficher les infos concernant la s�lection d'un objet
//			 */
//			System.out.println("Number: "+(int)buffer[i * 4]+
//					" \nMin Z: "+(float)buffer[i * 4 + 1]/2147483647+
//					" \nMax Z: " +(float)buffer[i * 4 + 2]/2147483647+
//					" \nName on stack: "+(int)buffer[i * 4 + 3]);

			int number=selectBuffer.get(offset);
			offset++;
			offset++;
			offset++;
			for(int j=0; j<number;j++)
			{
				int name = selectBuffer.get(offset);
				if(!selections.contains(name) && name!=0) selections.addElement(name);
				offset++;
			}


			/**
			 * on r�cup�re le num�ro de l'objet s�lectionn�
			 */
			//int name = (int)buffer[i * 4 + 3];
			//int name = selectBuffer.get(i*4+3);

			//if(!selections.contains(name) && name!=0) selections.addElement(name);
			//else
				//System.out.println(" "+name+" ");



		}
		//System.out.println();
		/**
		 * aucun objet � s�lectionner :-(
		 * et que l'on n'est pas en zone de s�lection
		 */
//		if (hits == 0 && !pickZone)
//		{
//			selections.removeAllElements();
//			System.out.println("erreur dans pick!");
//			//System.out.println("Rien du tout sous la souris\n");
//
//		}






	}




	private void afficherDansDisplay(GL gl, int mode)
	{

		/**
		 * afficher le rep�re
		 */
		//gl.glCallList(Dessin.REPERE);


		/**
		 * afficher un cube blanc au point o� l'on regarde (LookAt)
		 */
		/** 20080211 d�sactiver */
		//this.dessinerLookAt(gl);

		/**
		 * afficher la sc�ne de l'utilisateur
		 */
		afficherScene3DUtilisateur(gl);

		/**
		 * afficher les objets 3D
		 */
		Iterator<VisualObject> itConteneur = VisualObject.getConteneur_vobject().iterator();
		while(itConteneur.hasNext())
		{
			VisualObject objet3d = itConteneur.next();

			if(objet3d.isAfficher()) objet3d.dessiner(gl);


		}


	}


	private CountFPS getCountfps() {
		return countfps;
	}


	private void setCountfps(CountFPS countfps) {
		this.countfps = countfps;
	}



	/**
	 * retourne le nom de l'objet s�lectionn�
	 * @return
	 */
	protected int getSelectedVObject() {
		if(selections.isEmpty())
			return -1;
		else
		return (Integer)selections.firstElement();
	}

	/**
	 * retourne un vecteur de la liste des objets s�lectionn�s
	 * @return
	 */
	protected Collection<Integer> getSelectedVObjects() {
		return selections;
	}

	private void afficherScene3DUtilisateur(GL gl){

		getScene3DUtilisateur().afficherDansMaScene3D(gl);


	}

	protected Scene3DUtilisateurInterface getScene3DUtilisateur() {
		return scene3DUtilisateur;
	}

	protected void setScene3DUtilisateur(Scene3DUtilisateurInterface scene3DUtilisateur) {
		this.scene3DUtilisateur = scene3DUtilisateur;
	}

	  private void renderEyeScene(GL gl, int eyeType)
	  // draw the scene for the given eye camera
	  {
	    keyCamera.set(eyeType);
	        // set an eye camera's viewport, frustum, and position

	    // set light direction
	    gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, LIGHT_DIR, 0);


	  }  // end of renderEyeScene()




	/**
	 * @return the canvas
	 */
	public GLJPanel getCanvas() {
		return canvas;
	}




	/**
	 * @param canvas the canvas to set
	 */
	protected void setCanvas(GLJPanel canvas) {
		this.canvas = canvas;
	}

	private boolean isStereo()
	{
		return caps.getStereo();
	}

	private void setStereo(boolean stereoActivee)
	{
		caps.setStereo(stereoActivee);

	}



	/**
	 * @return the listCameras
	 */
	private  ArrayList<AbstractCamera> getListCameras() {
		return listCameras;
	}




	/**
	 * @param listCameras the listCameras to set
	 */
	private  void setListCameras(ArrayList<AbstractCamera> _listCameras) {
		listCameras = _listCameras;
	}






	protected void getOrthogonalDisplay()
	{
		GL gl = getCanvas().getGL();

		int currentWidth=getCanvas().getWidth();
		int currentHeight=getCanvas().getHeight();

        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();

        /** concerne toutes les cam�ras sauf 2D */
        if(this.getCurrentCamera().name.compareTo("2D")!=0)
        {

            gl.glOrtho(xNear/(ancHeight)*currentWidth,xFar/(ancHeight)*currentWidth,
        			yNear/(ancHeight)*currentHeight,yFar/(ancHeight)*currentHeight,
        			zFar,zNear);



            Dessin.glu.gluPerspective(30, currentWidth/currentHeight, 0.1, 1000);
        }
        else {

        	//Dessin.glu.gluOrtho2D(xNear,xFar,yNear,yFar);
                        gl.glOrtho(xNear/(ancHeight)*currentWidth,xFar/(ancHeight)*currentWidth,
        			yNear/(ancHeight)*currentHeight,yFar/(ancHeight)*currentHeight,
        			zNear,zFar);
//                Dessin.glu.gluOrtho2D(xNear/(ancHeight)*currentWidth,xFar/(ancHeight)*currentWidth,
//        			yNear/(ancHeight)*currentHeight,yFar/(ancHeight)*currentHeight);
        }



        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

	}

	private void dessinerLookAt(GL gl)
	{
		Dessin.drawCube(gl, (double)this.getCurrentCamera().getLookAtX(),
				 (double)this.getCurrentCamera().getLookAtY(),
				 (double)this.getCurrentCamera().getLookAtZ(),
				0.025, Couleur.BLANC);

	}

	/**
	 * d�sactiver les �couteurs sur la souris d'une cam�ra
	 * @param mouseHandler
	 */
	private void removeMouseHandlerCamera(AbstractCamera camera)
	{
		this.getCanvas().removeMouseListener(camera.getMouseHandler());
		this.getCanvas().removeMouseMotionListener(camera.getMouseHandler());
		this.getCanvas().removeMouseWheelListener(camera.getMouseHandler());


	}

	/**
	 * d�sactiver les �couteurs sur le clavier d'une cam�ra
	 * @param keyHandler
	 */
	private void removeKeyHandlerCamera(AbstractCamera camera)
	{

		this.getCanvas().removeKeyListener(camera.getKeyHandler());


	}

	/**
	 * activer les �couteurs sur la souris d'une cam�ra
	 * @param mouseHandler
	 */
	private void addMouseHandlerCamera(AbstractCamera camera)
	{
		this.getCanvas().addMouseListener(camera.getMouseHandler());
		this.getCanvas().addMouseMotionListener(camera.getMouseHandler());
		this.getCanvas().addMouseWheelListener(camera.getMouseHandler());


	}

	/**
	 * activer les �couteurs sur le clavier d'une cam�ra
	 * @param keyHandler
	 */
	private void addKeyHandlerCamera(AbstractCamera camera)
	{


		this.getCanvas().addKeyListener(camera.getKeyHandler());



	}


	  private void showOverlayInfo(GL gl)

	  {
	    // draw over the entire window
		int panelWidth = this.ancWidth; int panelHeight = this.ancHeight;
	    gl.glViewport(0, 0, panelWidth, panelHeight);
	    gl.glMatrixMode(GL.GL_PROJECTION);
	    gl.glLoadIdentity();

	    Graphics2D g2d = infoOverlay.createGraphics();

	    // clear the overlay
	    g2d.setComposite(AlphaComposite.Src);
	    g2d.setColor(new Couleur(1f,1f,1f,0.01f).getColor());//
	    g2d.fillRect(0, 0, this.ancWidth, this.ancHeight);


	    // draw camera info (in white)
	    g2d.setColor(new Couleur(0.5f,0.5f,0.5f,0.5f).getColor());
	    g2d.setFont(font);
	    //g2d.drawString( keyCamera.getPos(), 5, 15);
	    //g2d.drawString( keyCamera.getRots(), 5, 33);


            /**
             * definir couleur background texte affiché
             */
            Couleur couleurBackgroundTexte = new Couleur(1f,1f,0f,1f);
            /**
	     * afficher les coordonn�es de la cam�ra courante
	     */
            String infoCoordonnees = String.valueOf(" Camera("+String.format("%2.2f",getCurrentCamera().getEyeX())+
	    		";"+String.format("%2.2f",getCurrentCamera().getEyeY())+";"+
	    		String.format("%2.2f",getCurrentCamera().getEyeZ())+")");
            g2d.setColor(couleurBackgroundTexte.getColor());
            g2d.fillRect(5, 0,infoCoordonnees.length()*8,20);
            g2d.setColor(new Couleur(0f,0f,0f,1f).getColor());
	    g2d.drawString(infoCoordonnees,5,15);


	    /**
	     * afficher les coordonn�es du point horizon
	     */
            String infoHorizon = String.valueOf("Horizon("+String.format("%2.2f",getCurrentCamera().getLookAtX())+
	    		";"+String.format("%2.2f",getCurrentCamera().getLookAtY())+";"+
	    		String.format("%2.2f",getCurrentCamera().getLookAtZ())+")");
            g2d.setColor(couleurBackgroundTexte.getColor());
            g2d.fillRect(5, 15,infoHorizon.length()*8,20);
            g2d.setColor(new Couleur(0f,0f,0f,1f).getColor());
	    g2d.drawString(infoHorizon,5,30);

	    /**
	     * afficher le nom de la cam�ra et le nb de FPS
	     */
            String infoCamera = String.valueOf("Camera "+this.getCurrentCamera().getName()+" - FPS="+fps);
            g2d.setColor(couleurBackgroundTexte.getColor());
            g2d.fillRect(5, 30,infoCamera.length()*8,20);
            g2d.setColor(new Couleur(0f,0f,0f,1f).getColor());
	    g2d.drawString(infoCamera,5,45);
	    /**
	     * afficher le mode STEREO ou non // desactiver affichage indication
	     */
	    //g2d.drawString("Stereo " + String.valueOf(caps.getStereo()),5,60);
	    /**
             * afficher numéro de version sous la forme d'une date
             */
            //g2d.drawString("20090821", this.getCanvas().getWidth()-70,
	    //		this.getCanvas().getHeight()-14);


	    /**
	     * dessiner une zone de s�lection �  la souris pour la s�lection multiple
	     */
	    if(selectionMultiple)
	    {
	    	g2d.setColor(Couleur.RED.getColor()); // Couleur ROUGE
	    	g2d.drawRect(px, py, this.dragMouseCoordXY.x-px,this.dragMouseCoordXY.y-py);
	    	g2d.drawRect(px+1, py+1, this.dragMouseCoordXY.x-px,this.dragMouseCoordXY.y-py);
	    }

	    /**
	     * dessiner un disque de couleur pour avertir d'une s�lection d'objets
	     */
	    if(selections.isEmpty())
	    {
		    g2d.setColor(new Couleur(1f,0f,0f,1f).getColor());
	    	g2d.fillOval(this.getCanvas().getWidth()-30, 20, 20, 20);
	    }
	    else
	    {
		    g2d.setColor(new Couleur(0f,1f,0f,1f).getColor());
	    	g2d.fillOval(this.getCanvas().getWidth()-30,20, 20, 20);
	    }

	    if(!selections.isEmpty() && !selectionMultiple)
	    {
	    	String information=new String();
	    	String autreInformation=new String();
	    	if(this.getSelectedVObject()!=VisualObject.getConteneur_vobject().size())
	    	{
	    	 information=((VisualObject)VisualObject.getConteneur_vobject().get(this.getSelectedVObject()%VisualObject.getConteneur_vobject().size()-1)).getInformation();
	    	 autreInformation=((VisualObject)VisualObject.getConteneur_vobject().get(this.getSelectedVObject()%VisualObject.getConteneur_vobject().size()-1)).getAutreInformation();

	    	}
	    	 else
	    	 {
	    		 information=((VisualObject)VisualObject.getConteneur_vobject().get(this.getSelectedVObject()%VisualObject.getConteneur_vobject().size())).getInformation();
	    		 autreInformation=((VisualObject)VisualObject.getConteneur_vobject().get(this.getSelectedVObject()%VisualObject.getConteneur_vobject().size())).getAutreInformation();

	    	 }

//	    	g2d.setColor(new Couleur(1f,1f,0f,1f).getColor());
//	    	g2d.fillRect(5, this.getCanvas().getHeight()-28,5+information.length()*8,20);
//		    g2d.setColor(new Couleur(0f,0f,0f,1f).getColor());
//	    	g2d.drawString(information, 8,
//	    		this.getCanvas().getHeight()-14);
	    	g2d.setColor(new Couleur(1f,1f,0f,1f).getColor());
	    	g2d.fillRect((int)mouseCoordXY.getX()+10, (int)mouseCoordXY.getY(),information.length()*8,20);
		    g2d.setColor(new Couleur(0f,0f,0f,1f).getColor());
	    	g2d.drawString(information, (int)mouseCoordXY.getX()+10,
	    			(int)mouseCoordXY.getY()+14);
//	    	g2d.setColor(new Couleur(1f,1f,0f,1f).getColor());
//	    	g2d.fillRect((int)mouseCoordXY.getX()+10, (int)mouseCoordXY.getY()+15,autreInformation.length()*8,20);
//		    g2d.setColor(new Couleur(0f,0f,0f,1f).getColor());
//	    	g2d.drawString(autreInformation, (int)mouseCoordXY.getX()+10,
//	    			(int)mouseCoordXY.getY()+29);

	    }

	    // render all the overlay to the screen
	    infoOverlay.markDirty(0, 0, panelWidth, panelHeight);
	    infoOverlay.drawAll();

	    g2d.dispose();
	  }  // end of showOverlayInfo()


	  protected void viderSelectedVObjects()
	  {
		  selections.removeAllElements();
	  }
          
          
          
          
          
                class PopupListener extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
       //if(e.getButton()==e.BUTTON2)
      maybeShowPopup(e);
    }

    public void mouseReleased(MouseEvent e) {
        //if(e.getButton()==e.BUTTON2)
      maybeShowPopup(e);
    }

    private void maybeShowPopup(MouseEvent e) {
      if (e.isPopupTrigger())
        popup.show(e.getComponent(), e
            .getX(), e.getY());
    }
  }




        public void setPopup(JPopupMenu popup) {
        this.popup = popup;
        PopupListener pl = new PopupListener();
        this.getCanvas().addMouseListener(pl);
    }

}


